#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <glib.h>
#include <libsoup/soup.h>

#include "http.h"
#include "jsonrpc.h"
#include "util.h"

json_object *ajax(json_object *params) {
	const char *url = json_object_get_string(json_object_object_get(params, "url"));
	const char *method = json_object_get_string(json_object_object_get(params, "method"));
	json_object *headers = json_object_object_get(params, "headers");
	json_object *data = json_object_object_get(params, "data");
	json_object *cmd = json_object_object_get(params, "cmd");

	SoupSession *session = soup_session_sync_new();
	SoupMessage *msg = soup_message_new(g_strup((gchar *) method), url);

	if (headers) {
		json_object_object_foreach(headers, key, val)
		{
			soup_message_headers_append(msg->response_headers, key, json_object_get_string(val));
		}
	}

	if (data) {
		json_object_object_foreach(headers, key, val)
		{
			switch (json_object_get_type(val)) {
			case json_type_null:
			case json_type_boolean:
			case json_type_double:
			case json_type_int:
			case json_type_string: {
				GString *s = NULL;
				g_string_sprintf(s, "%s=%s", key, json_object_get_string(val));
				soup_message_body_append(msg->request_body, SOUP_MEMORY_TEMPORARY, s->str, s->len);
				g_string_free(s, TRUE);
				break;
			}
			case json_type_object:
			case json_type_array: {
				break;
			}
			default:
				break;
			}
		}
	}
	soup_session_send_message(session, msg);

	json_object *response = json_object_new_object();

	if (cmd) {
		const char *cmdname = json_object_get_string(json_object_object_get(cmd, "name"));
		if (g_strcasecmp(cmdname, "download") == 0) {
			const char *filename = json_object_get_string(json_object_object_get(cmd, "filename"));
			json_object *minsize = json_object_object_get(cmd, "minsize");
			gboolean ret = 0;
			if (!minsize || (minsize && msg->response_body->length >= json_object_get_int(minsize))) {
				ret = g_file_set_contents(filename, msg->response_body->data, msg->response_body->length, NULL);
			}
			json_object_object_add(response, "retval", json_object_new_int(ret));
		}
	} else {
		gchar *statusline = g_strdup_printf("HTTP/1.%d %d %s", soup_message_get_http_version(msg), msg->status_code,
				msg->reason_phrase);
		json_object_object_add(response, "statusline", json_object_new_string(statusline));
		g_free(statusline);

		json_object *response_headers = json_object_new_object();
		const char *name, *value;
		SoupMessageHeadersIter iter;
		soup_message_headers_iter_init(&iter, msg->response_headers);
		while (soup_message_headers_iter_next(&iter, &name, &value)) {
			if (g_strcasecmp(name, "Set-Cookie") == 0) {
				json_object *cookies = json_object_object_get(response_headers, "Set-Cookie");
				if (!cookies) {
					cookies = json_object_new_array();
					json_object_object_add(response_headers, name, cookies);
				}
				json_object_array_add(cookies, json_object_new_string(value));
			} else {
				json_object_object_add(response_headers, name, json_object_new_string(value));
			}
		}
		json_object_object_add(response, "headers", response_headers);

		json_object_object_add(response, "body",
				json_object_new_string_len(msg->response_body->data, msg->response_body->length));
	}

	g_object_unref(msg);
	soup_session_abort(session);
	g_object_unref(session);

	return response;
}

json_object *files(json_object *params) {
	const char *path = json_object_get_string(json_object_object_get(params, "path"));
	json_object *type = json_object_object_get(params, "type");
	int filetype = type ? json_object_get_int(type) : -1;
	GDir *dir;
	const char *filename;
	json_object *ret = NULL;

	/* File type */
	enum {
		DIR, FILE
	};

	dir = g_dir_open(path, 0, NULL);
	if (!dir) {
		return ret;
	}

	ret = json_object_new_array();
	while ((filename = g_dir_read_name(dir)) != NULL) {
		char *abs_path = g_build_filename(path, filename, NULL);
		int type = FILE;
		if (g_file_test(abs_path, G_FILE_TEST_IS_DIR)) {
			type = DIR;
		}
		if (filetype == type || (filetype != FILE && filetype != DIR)) {
			json_object *f = json_object_new_object();
			json_object_object_add(f, "type", json_object_new_int(type));
			json_object_object_add(f, "name", json_object_new_string(filename));
			json_object_array_add(ret, f);
		}
		g_free(abs_path);
	}
	g_dir_close(dir);

	return ret;
}

void jsonrpc_server_init(jsonrpc_server *server) {
	jsonrpc_init(server);

	jsonrpc_register_method(server, ajax, "ajax");
	jsonrpc_register_method(server, files, "files");
}
